home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / ANSI / c-client / tcp_vmsm.c < prev    next >
C/C++ Source or Header  |  1995-09-09  |  13KB  |  428 lines

  1. /*
  2.  * Program:    VMS TCP/IP routines for Multinet
  3.  *
  4.  * Author:    Yehavi Bourvine, The Hebrew University of Jerusalem
  5.  *        Internet: Yehavi@VMS.huji.ac.il
  6.  *
  7.  * Date:    2 August 1994
  8.  * Last Edited:    8 September 1995
  9.  *
  10.  * Copyright 1995 by the University of Washington
  11.  *
  12.  *  Permission to use, copy, modify, and distribute this software and its
  13.  * documentation for any purpose and without fee is hereby granted, provided
  14.  * that the above copyright notice appears in all copies and that both the
  15.  * above copyright notice and this permission notice appear in supporting
  16.  * documentation, and that the name of the University of Washington not be
  17.  * used in advertising or publicity pertaining to distribution of the software
  18.  * without specific, written prior permission.  This software is made available
  19.  * "as is", and
  20.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  21.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  22.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  23.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  24.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  25.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  26.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  27.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  28.  *
  29.  */
  30.  
  31.                 /* TCP timeout handler routine */
  32. static tcptimeout_t tcptimeout = NIL;
  33.                 /* TCP timeouts, in seconds */
  34. static long tcptimeout_read = 0;
  35. static long tcptimeout_write = 0;
  36.  
  37. /* TCP/IP manipulate parameters
  38.  * Accepts: function code
  39.  *        function-dependent value
  40.  * Returns: function-dependent return value
  41.  */
  42.  
  43. void *tcp_parameters (long function,void *value)
  44. {
  45.   switch ((int) function) {
  46.   case SET_TIMEOUT:
  47.     tcptimeout = (tcptimeout_t) value;
  48.     break;
  49.   case GET_TIMEOUT:
  50.     value = (void *) tcptimeout;
  51.     break;
  52.   case SET_READTIMEOUT:
  53.     tcptimeout_read = (long) value;
  54.     break;
  55.   case GET_READTIMEOUT:
  56.     value = (void *) tcptimeout_read;
  57.     break;
  58.   case SET_WRITETIMEOUT:
  59.     tcptimeout_write = (long) value;
  60.     break;
  61.   case GET_WRITETIMEOUT:
  62.     value = (void *) tcptimeout_write;
  63.     break;
  64.   default:
  65.     value = NIL;        /* error case */
  66.     break;
  67.   }
  68.   return value;
  69. }
  70.  
  71. /* TCP/IP open
  72.  * Accepts: host name
  73.  *        contact service name
  74.  *        contact port number
  75.  * Returns: TCP/IP stream if success else NIL
  76.  */
  77.  
  78. TCPSTREAM *tcp_open (char *host,char *service,long port)
  79. {
  80.   TCPSTREAM *stream = NIL;
  81.   int sock;
  82.   char *s;
  83.   struct sockaddr_in sin;
  84.   struct hostent *host_name;
  85.   char hostname[MAILTMPLEN];
  86.   char tmp[MAILTMPLEN];
  87.   struct protoent *pt = getprotobyname ("ip");
  88.   struct servent *sv = service ? getservbyname (service,"tcp") : NIL;
  89.   if (s = strchr (host,':')) {    /* port number specified? */
  90.     *s++ = '\0';        /* yes, tie off port */
  91.     port = strtol (s,&s,10);    /* parse port */
  92.     if (s && *s) {
  93.       sprintf (tmp,"Junk after port number: %.80s",s);
  94.       mm_log (tmp,ERROR);
  95.       return NIL;
  96.     }
  97.     sin.sin_port = htons (port);
  98.   }
  99.                 /* copy port number in network format */
  100.   else sin.sin_port = sv ? sv->s_port : htons (port);
  101.   /* The domain literal form is used (rather than simply the dotted decimal
  102.      as with other Unix programs) because it has to be a valid "host name"
  103.      in mailsystem terminology. */
  104.                 /* look like domain literal? */
  105.   if (host[0] == '[' && host[(strlen (host))-1] == ']') {
  106.     strcpy (hostname,host+1);    /* yes, copy number part */
  107.     hostname[(strlen (hostname))-1] = '\0';
  108.     if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
  109.       sin.sin_family = AF_INET;    /* family is always Internet */
  110.       strcpy (hostname,host);    /* hostname is user's argument */
  111.     }
  112.     else {
  113.       sprintf (tmp,"Bad format domain-literal: %.80s",host);
  114.       mm_log (tmp,ERROR);
  115.       return NIL;
  116.     }
  117.   }
  118.  
  119.   else {            /* lookup host name, note that brain-dead Unix
  120.                    requires lowercase! */
  121.     strcpy (hostname,host);    /* in case host is in write-protected memory */
  122.     if ((host_name = gethostbyname (lcase (hostname)))) {
  123.                 /* copy address type */
  124.       sin.sin_family = host_name->h_addrtype;
  125.                 /* copy host name */
  126.       strcpy (hostname,host_name->h_name);
  127.                 /* copy host addresses */
  128.       memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
  129.     }
  130.     else {
  131.       sprintf (tmp,"No such host as %.80s",host);
  132.       mm_log (tmp,ERROR);
  133.       return NIL;
  134.     }
  135.   }
  136.                 /* get a TCP stream */
  137.   if ((sock = socket (sin.sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
  138.     sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
  139.     mm_log (tmp,ERROR);
  140.     return NIL;
  141.   }
  142.                 /* open connection */
  143.   if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
  144.     sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
  145.          strerror (errno));
  146.     mm_log (tmp,ERROR);
  147.     return NIL;
  148.   }
  149.                 /* create TCP/IP stream */
  150.   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
  151.                 /* copy official host name */
  152.   stream->host = cpystr (hostname);
  153.                 /* get local name */
  154.   gethostname (tmp,MAILTMPLEN-1);
  155.   stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
  156.                   host_name->h_name : tmp);
  157.                 /* init sockets */
  158.   stream->port = port;        /* port number */
  159.   stream->tcpsi = stream->tcpso = sock;
  160.   stream->ictr = 0;        /* init input counter */
  161.   return stream;        /* return success */
  162. }
  163.  
  164. /* TCP/IP authenticated open
  165.  * Accepts: host name
  166.  *        service name
  167.  *        returned user name
  168.  * Returns: TCP/IP stream if success else NIL
  169.  */
  170.  
  171. TCPSTREAM *tcp_aopen (char *host,char *service,char *usrnam)
  172. {
  173.     return NIL;
  174. }
  175.  
  176. /* TCP/IP receive line
  177.  * Accepts: TCP/IP stream
  178.  * Returns: text line string or NIL if failure
  179.  */
  180.  
  181. char *tcp_getline (TCPSTREAM *stream)
  182. {
  183.   int n,m;
  184.   char *st,*ret,*stp;
  185.   char c = '\0';
  186.   char d;
  187.                 /* make sure have data */
  188.   if (!tcp_getdata (stream)) return NIL;
  189.   st = stream->iptr;        /* save start of string */
  190.   n = 0;            /* init string count */
  191.   while (stream->ictr--) {    /* look for end of line */
  192.     d = *stream->iptr++;    /* slurp another character */
  193.     if ((c == '\015') && (d == '\012')) {
  194.       ret = (char *) fs_get (n--);
  195.       memcpy (ret,st,n);    /* copy into a free storage string */
  196.       ret[n] = '\0';        /* tie off string with null */
  197.       return ret;
  198.     }
  199.     n++;            /* count another character searched */
  200.     c = d;            /* remember previous character */
  201.   }
  202.                 /* copy partial string from buffer */
  203.   memcpy ((ret = stp = (char *) fs_get (n)),st,n);
  204.                 /* get more data from the net */
  205.   if (!tcp_getdata (stream)) fs_give ((void **) &ret);
  206.                 /* special case of newline broken by buffer */
  207.   else if ((c == '\015') && (*stream->iptr == '\012')) {
  208.     stream->iptr++;        /* eat the line feed */
  209.     stream->ictr--;
  210.     ret[n - 1] = '\0';        /* tie off string with null */
  211.   }
  212.                 /* else recurse to get remainder */
  213.   else if (st = tcp_getline (stream)) {
  214.     ret = (char *) fs_get (n + 1 + (m = strlen (st)));
  215.     memcpy (ret,stp,n);        /* copy first part */
  216.     memcpy (ret + n,st,m);    /* and second part */
  217.     fs_give ((void **) &stp);    /* flush first part */
  218.     fs_give ((void **) &st);    /* flush second part */
  219.     ret[n + m] = '\0';        /* tie off string with null */
  220.   }
  221.   return ret;
  222. }
  223.  
  224. /* TCP/IP receive buffer
  225.  * Accepts: TCP/IP stream
  226.  *        size in bytes
  227.  *        buffer to read into
  228.  * Returns: T if success, NIL otherwise
  229.  */
  230.  
  231. long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
  232. {
  233.   unsigned long n;
  234.   char *bufptr = buffer;
  235.   while (size > 0) {        /* until request satisfied */
  236.     if (!tcp_getdata (stream)) return NIL;
  237.     n = min (size,stream->ictr);/* number of bytes to transfer */
  238.                 /* do the copy */
  239.     memcpy (bufptr,stream->iptr,n);
  240.     bufptr += n;        /* update pointer */
  241.     stream->iptr +=n;
  242.     size -= n;            /* update # of bytes to do */
  243.     stream->ictr -=n;
  244.   }
  245.   bufptr[0] = '\0';        /* tie off string */
  246.   return T;
  247. }
  248.  
  249. /* TCP/IP receive data
  250.  * Accepts: TCP/IP stream
  251.  * Returns: T if success, NIL otherwise
  252.  */
  253.  
  254. long tcp_getdata (TCPSTREAM *stream)
  255. {
  256.   int i;
  257.   fd_set fds,efds;
  258.   struct timeval tmo;
  259.   time_t t = time (0);
  260.   tmo.tv_sec = tcptimeout_read;
  261.   tmo.tv_usec = 0;
  262.   FD_ZERO (&fds);        /* initialize selection vector */
  263.   FD_ZERO (&efds);        /* handle errors too */
  264.   if (stream->tcpsi < 0) return NIL;
  265.   while (stream->ictr < 1) {    /* if nothing in the buffer */
  266.     FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
  267.     FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
  268.     errno = NIL;        /* block and read */
  269.     while (((i = select (getdtablesize (),&fds,0,&efds,tmo.tv_sec ? &tmo:0))<0)
  270.        && (errno == EINTR));
  271.     if (!i) {            /* timeout? */
  272.       if (tcptimeout && ((*tcptimeout) (time (0) - t))) continue;
  273.       else return tcp_abort (stream);
  274.     }
  275.     if (i < 0) return tcp_abort (stream);
  276.     while (((i = socket_read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
  277.        (errno == EINTR));
  278.     if (i < 1) return tcp_abort (stream);
  279.     stream->iptr = stream->ibuf;/* point at TCP buffer */
  280.     stream->ictr = i;        /* set new byte count */
  281.   }
  282.   return T;
  283. }
  284.  
  285. /* TCP/IP send string as record
  286.  * Accepts: TCP/IP stream
  287.  *        string pointer
  288.  * Returns: T if success else NIL
  289.  */
  290.  
  291. long tcp_soutr (TCPSTREAM *stream,char *string)
  292. {
  293.   return tcp_sout (stream,string,(unsigned long) strlen (string));
  294. }
  295.  
  296.  
  297. /* TCP/IP send string
  298.  * Accepts: TCP/IP stream
  299.  *        string pointer
  300.  *        byte count
  301.  * Returns: T if success else NIL
  302.  */
  303.  
  304. long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
  305. {
  306.   int i;
  307.   fd_set fds;
  308.   struct timeval tmo;
  309.   time_t t = time (0);
  310.   tmo.tv_sec = tcptimeout_write;
  311.   tmo.tv_usec = 0;
  312.   FD_ZERO (&fds);        /* initialize selection vector */
  313.   if (stream->tcpso < 0) return NIL;
  314.   while (size > 0) {        /* until request satisfied */
  315.     FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
  316.     errno = NIL;        /* block and write */
  317.     while (((i = select (getdtablesize (),0,&fds,0,tmo.tv_sec ? &tmo : 0)) < 0)
  318.        && (errno == EINTR));
  319.     if (!i) {            /* timeout? */
  320.       if (tcptimeout && ((*tcptimeout) (time (0) - t))) continue;
  321.       else return tcp_abort (stream);
  322.     }
  323.     if (i < 0) return tcp_abort (stream);
  324.     while (((i = socket_write (stream->tcpso,string,size)) < 0) &&
  325.        (errno == EINTR));
  326.     if (i < 0) return tcp_abort (stream);
  327.     size -= i;            /* how much we sent */
  328.     string += i;
  329.   }
  330.   return T;            /* all done */
  331. }
  332.  
  333. /* TCP/IP close
  334.  * Accepts: TCP/IP stream
  335.  */
  336.  
  337. void tcp_close (TCPSTREAM *stream)
  338. {
  339.   tcp_abort (stream);        /* nuke the stream */
  340.                 /* flush host names */
  341.   fs_give ((void **) &stream->host);
  342.   fs_give ((void **) &stream->localhost);
  343.   fs_give ((void **) &stream);    /* flush the stream */
  344. }
  345.  
  346.  
  347. /* TCP/IP abort stream
  348.  * Accepts: TCP/IP stream
  349.  * Returns: NIL always
  350.  */
  351.  
  352. long tcp_abort (TCPSTREAM *stream)
  353. {
  354.   int i;
  355.   if (stream->tcpsi >= 0) {    /* no-op if no socket */
  356.                 /* nuke the socket */
  357.     socket_close (stream->tcpsi);
  358.     if (stream->tcpsi != stream->tcpso) socket_close (stream->tcpso);
  359.     stream->tcpsi = stream->tcpso = -1;
  360.   }
  361.   return NIL;
  362. }
  363.  
  364. /* TCP/IP get host name
  365.  * Accepts: TCP/IP stream
  366.  * Returns: host name for this stream
  367.  */
  368.  
  369. char *tcp_host (TCPSTREAM *stream)
  370. {
  371.   return stream->host;        /* return host name */
  372. }
  373.  
  374.  
  375. /* TCP/IP return port for this stream
  376.  * Accepts: TCP/IP stream
  377.  * Returns: port number for this stream
  378.  */
  379.  
  380. long tcp_port (TCPSTREAM *stream)
  381. {
  382.   return stream->port;        /* return port number */
  383. }
  384.  
  385.  
  386. /* TCP/IP get local host name
  387.  * Accepts: TCP/IP stream
  388.  * Returns: local host name
  389.  */
  390.  
  391. char *tcp_localhost (TCPSTREAM *stream)
  392. {
  393.   return stream->localhost;    /* return local host name */
  394. }
  395.  
  396. /* TCP/IP get server host name
  397.  * Accepts: pointer to destination
  398.  * Returns: string pointer if got results, else NIL
  399.  */
  400.  
  401. char *tcp_clienthost (char *dst)
  402. {
  403.   struct hostent *hn;
  404.   struct sockaddr_in from;
  405.   int fromlen = sizeof (from);
  406.   if (getpeername (0,(struct sockaddr *) &from,&fromlen)) return "UNKNOWN";
  407.   strcpy (dst,(hn = gethostbyaddr ((char *) &from.sin_addr,
  408.                    sizeof (struct in_addr),from.sin_family)) ?
  409.       hn->h_name : inet_ntoa (from.sin_addr));
  410.   return dst;
  411. }
  412.  
  413.  
  414. /* Return my local host name
  415.  * Returns: my local host name
  416.  */
  417.  
  418. char *mylocalhost ()
  419. {
  420.   char tmp[MAILTMPLEN];
  421.   struct hostent *hn;
  422.   if (!myLocalHost) {        /* have local host yet? */
  423.     gethostname(tmp,MAILTMPLEN);/* get local host name */
  424.     myLocalHost = cpystr ((hn = gethostbyname (tmp)) ? hn->h_name : tmp);
  425.   }
  426.   return myLocalHost;
  427. }
  428.